package com.geneqiao.jdbc.pool;

import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import java.util.Properties;

import org.apache.log4j.Logger;

import com.geneqiao.jdbc.jpa.ReflectJPA;
import com.geneqiao.jdbc.jpa.TableStruct;
import com.geneqiao.jdbc.util.EntityUtils;

public class JDBCDataSource
{

	// 日志
	private static final Logger logger = Logger.getLogger(JDBCDataSource.class);
	private static final String defaultConfig = "jdbc.properties";
	private JDBCPool jdbcPool;

	private String driverClassName;
	private String url;
	private String username;
	private String password;
	private String entities;
	private int maxIdle;
	private int maxActive;
	private boolean withSpring;

	public JDBCDataSource()
	{
		this.withSpring = true;
		logger.debug("Building with springframework...");
	}

	private JDBCDataSource(String fileName)
	{
		try
		{
			Properties prop = new Properties();
			// 在静态代码块中加载db.properties数据库配置文件
			InputStream in = JDBCDataSource.class.getClassLoader().getResourceAsStream(fileName);
			prop.load(in);
			this.jdbcPool = new JDBCPool(prop);
			cacheEntities(prop);
		}
		catch (Exception e)
		{
			logger.error("初始化配置文件失败", e);
		}

	}

	private void cacheEntities(Properties prop)
	{
		String _entities = prop.getProperty("project.entities");
		if (_entities == null || "".equals(_entities))
		{
			if (logger.isDebugEnabled())
				logger.debug("The project.entities attribute was not found");
			return;
		}

		List<Class<?>> classes;
		if (_entities.endsWith(".*"))
			classes = EntityUtils.scanEntities(_entities.substring(0, _entities.length() - 2));
		else
			classes = EntityUtils.splitEntities(_entities);
		TableStruct struct;
		for (Class<?> cla : classes)
		{
			struct = ReflectJPA.loadTable(cla);
			if (struct != null)
			{
				JDBCMap.addEntity(cla.getName(), struct);
				if (logger.isDebugEnabled())
					logger.debug("Load entity '" + cla.getName() + "'");
			}
		}
	}

	public static JDBCDataSource getInstance(String fileName)
	{
		return new JDBCDataSource(fileName);
	}

	public static JDBCDataSource getInstance()
	{
		return getInstance(defaultConfig);
	}

	public synchronized Connection getConnection()
	{
		try
		{
			if (withSpring && jdbcPool == null)
			{
				Properties ps = new Properties();
				ps.put("datasource.driverClassName", driverClassName);
				ps.put("datasource.url", url);
				ps.put("datasource.username", username);
				ps.put("datasource.password", password);
				ps.put("datasource.maxActive", maxActive + "");
				ps.put("datasource.maxIdle", maxIdle + "");
				ps.put("project.entities", entities + "");
				jdbcPool = new JDBCPool(ps);
				cacheEntities(ps);
			}
			return jdbcPool.getConnection();
		}
		catch (SQLException | ClassNotFoundException | InterruptedException e)
		{
			logger.error("获取数据库链接失败", e);
		}
		return null;
	}
	
	public synchronized SelectConn getSelectConnection()
	{
		try
		{
			if (withSpring && jdbcPool == null)
			{
				Properties ps = new Properties();
				ps.put("datasource.driverClassName", driverClassName);
				ps.put("datasource.url", url);
				ps.put("datasource.username", username);
				ps.put("datasource.password", password);
				ps.put("datasource.maxActive", maxActive + "");
				ps.put("datasource.maxIdle", maxIdle + "");
				ps.put("project.entities", entities + "");
				jdbcPool = new JDBCPool(ps);
				cacheEntities(ps);
			}
			return jdbcPool.getSelectConnection();
		}
		catch (SQLException | ClassNotFoundException e)
		{
			logger.error("获取Select链接失败", e);
		}
		return null;
	}

	public void releaseConnection(Connection conn)
	{
		if (conn == null)
			return;
		try
		{
			jdbcPool.releaseConnection(conn);
		}
		catch (SQLException e)
		{
			logger.error("Release connection faild", e);
		}
	}

	public static void close(Connection conn)
	{
		if(conn == null)
			return;
		try
		{
			conn.close();
		}
		catch (SQLException e)
		{
			logger.error("Close connection faild", e);
		}
	}

	public void shutdown()
	{
		jdbcPool.shutdown();
	}

	public static void rollback(Connection conn)
	{
		try
		{
			conn.rollback();
		}
		catch (Exception e)
		{
			logger.error("Rollback faild", e);
		}
	}

	public void setAutoCommit(Connection conn)
	{
		try
		{
			conn.setAutoCommit(true);
		}
		catch (Exception e)
		{
			logger.error("SetAutoCommit faild", e);
		}
	}

	public void close()
	{
		jdbcPool.shutdown();
	}

	public String getDriverClassName()
	{
		return driverClassName;
	}

	public void setDriverClassName(String driverClassName)
	{
		this.driverClassName = driverClassName;
	}

	public String getUrl()
	{
		return url;
	}

	public void setUrl(String url)
	{
		this.url = url;
	}

	public String getUsername()
	{
		return username;
	}

	public void setUsername(String username)
	{
		this.username = username;
	}

	public String getPassword()
	{
		return password;
	}

	public void setPassword(String password)
	{
		this.password = password;
	}

	public int getMaxIdle()
	{
		return maxIdle;
	}

	public void setMaxIdle(int maxIdle)
	{
		this.maxIdle = maxIdle;
	}

	public int getMaxActive()
	{
		return maxActive;
	}

	public void setMaxActive(int maxActive)
	{
		this.maxActive = maxActive;
	}

	public String getEntities()
	{
		return entities;
	}

	public void setEntities(String entities)
	{
		this.entities = entities;
	}
}
